package cn.lingyangwl.agile.file.excel;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.handler.inter.IExcelDictHandler;
import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.agile.common.core.exception.enums.GlobalErrorEnum;
import cn.lingyangwl.agile.model.ExcelBaseModel;
import cn.lingyangwl.framework.core.utils.spring.SpringUtils;
import cn.lingyangwl.framework.tool.core.*;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Slf4j
@Component
public class CusExcelImportUtil {

    private static IExcelDictHandler excelDictHandler;

    @PostConstruct
    public void init() {
        try {
            excelDictHandler = SpringUtils.getBean(IExcelDictHandler.class);
        } catch (Exception e) {
            log.warn(e.getMessage());
        }
        if (Objects.isNull(excelDictHandler)) {
            log.warn("未发现表格导出导入字典处理器");
        }
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class UniqueField {
        private Excel excel;
        private ExcelUnique excelUnique;
        private Field field;

        public void setField() {

        }

        public static UniqueField gen(Field field) {
            ExcelUnique excelUnique = field.getAnnotation(ExcelUnique.class);
            Excel excel = field.getAnnotation(Excel.class);
            field.setAccessible(true);
            if (Objects.nonNull(excelUnique) && Objects.nonNull(excel)) {
                return UniqueField.builder().excelUnique(excelUnique).excel(excel).field(field).build();
            }
            return null;
        }
    }

    public static <T extends ExcelBaseModel> List<T> getList(ImportParams importParams, InputStream in, Class<T> cla) throws Exception {
        importParams.setNeedVerify(true);
        importParams.setDictHandler(excelDictHandler);
        int index = importParams.getStartSheetIndex();
        ExcelImportResult<T> importResult = ExcelImportUtil.importExcelMore(in, cla, importParams);
        if (importResult == null) {
            throw new BizException(GlobalErrorEnum.EXCEL_IMPORT_FAIL, "数据为空, 导入无效");
        }

        // 处理校验错误的数据
        List<String> errorList = new ArrayList<>();
        if (CollUtil.isNotEmpty(importResult.getFailList())) {
            for (ExcelBaseModel entity : importResult.getFailList()) {
                int line = entity.getRowNum() + 1;
                String msg = "【sheet" + (index + 1) + "】第" + line + "行：" + entity.getErrorMsg();
                errorList.add(msg);
            }
        }
        if (CollUtil.isNotEmpty(errorList)) {
            throw new BizException(GlobalErrorEnum.EXCEL_IMPORT_FAIL, String.join("<br/>", errorList));
        }

        // 校验重复数据
        List<Field> fields = ReflectUtils.getFields(cla);
        List<UniqueField> uniqueFields = fields.stream().map(UniqueField::gen).filter(Objects::nonNull).collect(Collectors.toList());;
        Map<String, Integer> fieldMap = new HashMap<>();
        String uniqueFieldNameStr = uniqueFields.stream().map(e -> e.getExcel().name()).collect(Collectors.joining("、"));

        for (ExcelBaseModel entity : importResult.getList()) {
            int line = entity.getRowNum() + 1;
            // 数据重复性校验
            String key = uniqueFields.stream().map(e -> {
                try {
                    return e.getField().get(entity);
                } catch (Exception ex) {
                    log.warn("error: ", ex);
                    return null;
                }
            }).filter(Objects::nonNull).map(String::valueOf).collect(Collectors.joining());
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            Integer exitDataRowNum = fieldMap.get(key);
            if (Objects.nonNull(exitDataRowNum)) {
                String msg = String.format("【sheet%s】第%s行 与 第%s行数据重复 (%s 必须联合唯一)",
                    index + 1, line, exitDataRowNum, uniqueFieldNameStr);
                errorList.add(msg);
            }
            fieldMap.put(key, line);
        }
        if (CollUtil.isNotEmpty(errorList)) {
            throw new BizException(GlobalErrorEnum.EXCEL_IMPORT_FAIL, String.join("<br/>", errorList));
        }
        return importResult.getList();
    }
}
